/* ======================================================================================== *\

		FILE:				ForwardRenderer.cpp
		AUTHOR:				Jack Hoxley

		DESCRIPTION:		An implementation of traditional forward rendering.

		CHANGE:				14th July 2007
								Implemented basic interface
							27th July 2007
								Migrated geometry creation code to create proper
								cylinders instead of line-lists.
							25th August 2007
								Got vertex-blended joints working for cylinders!
							27th August 2007
								Factored out some constants to Constants.h
							8th September 2007
								Code now calculates and transforms per-vertex normals

\* ======================================================================================== */

// Include Standard Headers
// ------------------------
#include "DXUT.h"

#pragma warning( disable : 4995 ) // Not interested in deprectation warnings
#include <sstream>
#pragma warning( default : 4995 )


// Include project headers
// -----------------------
#include "Utils.h"
#include "Profiling.h"
#include "PipeLayout.h"
#include "PipeRenderer.h"
#include "ForwardRenderer.h"
#include "Constants.h"


namespace Renderer
{

	ForwardRenderer::ForwardRenderer( )
	{
		INFO_OUT( L"Creating forward rendering class..." );

		m_PipeCount = 0;
		m_ppPipe = NULL;
		m_pEffect = NULL;
		m_VRAMBytes = 0;
	}



	ForwardRenderer::~ForwardRenderer( )
	{
		INFO_OUT( L"Destroying forward rendering class..." );
	}



	HRESULT ForwardRenderer::CreateResources( ID3D10Device* pDevice, const PipeSim::PipeLayout * const p )
	{
		// 0] General initialization
		// -------------------------
		HRESULT	hr = S_OK;
		m_VRAMBytes = 0;

		hr = DestroyResources( );

		if( FAILED( hr ) )
		{
			ERR_OUT( L"Failed to destroy resources before creating new ones." );

			return hr;
		}

		// 1] Create the rendering effect
		// ------------------------------
		UINT uiHLSLFlags = D3D10_SHADER_ENABLE_STRICTNESS;
#ifdef _DEBUG
		uiHLSLFlags |= D3D10_SHADER_DEBUG;
#endif
		UINT uiFXFlags = 0;

		ID3D10Blob* pErrors = NULL;

		hr = D3DX10CreateEffectFromFile( L"ForwardRendering.fx", NULL, NULL, "fx_4_0", uiHLSLFlags, uiFXFlags, pDevice, NULL, NULL, &m_pEffect, &pErrors, NULL );
		if( FAILED( hr ) )
		{
			ERR_OUT( L"Failed to create and compile 'ForwardRendering.fx'" );

			if( NULL != pErrors )
			{
				// We can output any compilation messages
				char* pMessages = reinterpret_cast< char* >( pErrors->GetBufferPointer( ) );

				OutputDebugStringA( pMessages );
			}

			return hr;
		}



		// 2] Create each pipe
		// -------------------
		UINT16 MaximumPipeLength = p->LayoutXDimension() * p->LayoutYDimension() * p->LayoutZDimension();

		m_PipeCount = p->NumberOfPipes();

		m_ppPipe = new PipeResources*[ m_PipeCount ];

		// BUGFIX: If an error occurs on one pipe then subsequent ones are
		// initialized by the preceding statement. This causes errors when
		// calling DestroyResources(). Simple fix is to zero out all elements
		// so that  a ==NULL test can be used to skip attempting to destroy any
		// uncreated entries.

		for( UINT16 i = 0; i < m_PipeCount; ++i )
		{
			m_ppPipe[i] = new PipeResources;

			// Zero-out the values in case CreateIndividualPipe() fails
			m_ppPipe[i]->m_IndexCount = 0;
			m_ppPipe[i]->m_LastUpdated = 0;
			m_ppPipe[i]->m_pIndexBuffer = NULL;
			m_ppPipe[i]->m_PipeLength = 0;
			m_ppPipe[i]->m_ppInputLayouts = NULL;
			m_ppPipe[i]->m_pTechnique = NULL;
			m_ppPipe[i]->m_pVertexBuffer = NULL;
			m_ppPipe[i]->m_VertexCount = 0;
		}

		for( UINT16 i = 0; i < m_PipeCount; ++i )
		{
			hr = CreateIndividualPipe( m_ppPipe[i], MaximumPipeLength, pDevice );

			if( FAILED( hr ) )
			{
				ERR_OUT( L"Failed to create individual pipe!" );

				SAFE_RELEASE( m_pEffect );

				return hr;
			}
		}

		return S_OK;
	}



	HRESULT ForwardRenderer::UpdateResources( const PipeSim::PipeLayout * const p )
	{
		// Scan each pipe in the simulation
		for( UINT16 i = 0; i < p->NumberOfPipes(); ++i )
		{
			// Determine when it was last updated by the simulation
			// If that is after the time we last updated the renderable
			// geometry then we need to flag this pipe as dirty and
			// update accordingly...
			UINT32 LastChanged = p->IterationOfLastChange( i );
			if( LastChanged > m_ppPipe[i]->m_LastUpdated )
			{
				// Simulation is ahead of renderable geometry. This pipe
				// must be updated.
#ifdef DEBUG
				{
					std::wostringstream woss;
					woss << L"Simulation and rendering out of sync for pipe #" << i << L". Simulation: " << p->IterationOfLastChange(i) << L", renderable: " << m_ppPipe[i]->m_LastUpdated;
					Utils::OutputMessage( Utils::Information, WIDEN( __FUNCTION__ ), __LINE__, woss.str().c_str() );
				}
#endif
				// Request an array of coordinates for the current pipe.
				// Do this as a single batch request so as to leave the door open
				// at a later date to implement a multi-threaded architecture...
				Utils::CoordinateList pCoords( p->LayoutXDimension() * p->LayoutYDimension() * p->LayoutZDimension() );
				p->GetPipeCoordinates( i, &pCoords );

				// We can now update the pipe with the new coordinates
				if( FAILED( UpdateIndividualPipe( m_ppPipe[i], pCoords, p->LayoutXDimension(), p->LayoutYDimension(), p->LayoutZDimension(), p->PipeLength( i ) ) ) )
				{
					// Not strictly a fatal error, so just issue a debug warning...
					WARN_OUT( L"Unable to update individual pipe!" );
				}
				else
				{
					// Pipe was successfully updated, so we need to ensure
					// the last updated field is correct.
					m_ppPipe[i]->m_LastUpdated = LastChanged;
				}
			}
		}
		return S_OK;
	}



	HRESULT ForwardRenderer::DestroyResources()
	{
		for( UINT16 i = 0; i < m_PipeCount; ++i )
		{
			// Release resources contained within the struct
			if( FAILED( DestroyIndividualPipe( m_ppPipe[i] ) ) )
			{
				ERR_OUT( L"Failed to release individual pipe resources!" );

				return E_FAIL;
			}

			// Delete the actual struct
			SAFE_DELETE( m_ppPipe[i] );
		}
		SAFE_DELETE_ARRAY( m_ppPipe );

		SAFE_RELEASE( m_pEffect );
		return S_OK;
	}



	HRESULT ForwardRenderer::Render( ID3D10Device* pDevice, D3DXMATRIX& mViewProj )
	{
		// Configure any 'global' effect variables
		m_pEffect->GetVariableByName("mViewProj")->AsMatrix()->SetMatrix( mViewProj );

		// Moving this statement outside of the stateblock stops the following debug warning:
		// [ STATE_SETTING INFO #237: DEVICE_IASETPRIMITIVETOPOLOGY_TOPOLOGY_UNDEFINED ]
		pDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST );

		// Now perform the actual rendering
		for( UINT16 pipe = 0; pipe < m_PipeCount; ++pipe )
		{
			D3D10_STATE_BLOCK_MASK mask;
			m_ppPipe[pipe]->m_pTechnique->ComputeStateBlockMask( &mask );

			D3D10_TECHNIQUE_DESC techDesc;
			m_ppPipe[pipe]->m_pTechnique->GetDesc( &techDesc );

			for( UINT pass = 0; pass < techDesc.Passes; ++pass )
			{
				ID3D10StateBlock* pStateBlock = NULL;

				if( SUCCEEDED( D3D10CreateStateBlock( pDevice, &mask, &pStateBlock ) ) )
				{
					if( SUCCEEDED( pStateBlock->Capture() ) )
					{	
						if( SUCCEEDED( m_ppPipe[pipe]->m_pTechnique->GetPassByIndex(pass)->Apply(0) ) )
						{
							// Configure the input assembler
							pDevice->IASetInputLayout( m_ppPipe[pipe]->m_ppInputLayouts[pass] );
							pDevice->IASetIndexBuffer( m_ppPipe[pipe]->m_pIndexBuffer, DXGI_FORMAT_R32_UINT, 0 );
							UINT stride = sizeof( SimpleVertex );
							UINT offset = 0;
							pDevice->IASetVertexBuffers( 0, 1, &m_ppPipe[pipe]->m_pVertexBuffer, &stride, &offset );
							pDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST );

							// Finally issue the actual draw-call
							UINT IndexCount = ( 1 + Constants::StacksPerPipeSegment ) * (6 * Constants::SlicesPerPipeSegment) * m_ppPipe[pipe]->m_PipeLength;
							pDevice->DrawIndexed( IndexCount, 0, 0 );
						}

						pStateBlock->Apply( );
					}
				}

				SAFE_RELEASE( pStateBlock );
			}
		}

		return S_OK;
	}



	UINT32 ForwardRenderer::VideoMemoryStorageInUse()
	{
		return m_VRAMBytes;
	}



	void ForwardRenderer::RendererName( wchar_t* wcDestination, const size_t& DestinationSize )
	{
		wcscpy_s( wcDestination, DestinationSize, L"Forward Renderer" );
	}


	HRESULT ForwardRenderer::CreateIndividualPipe( PipeResources* p, const UINT16& MaximumPipeLength, ID3D10Device* pDevice )
	{
		// 1] Initialization
		// -----------------
		if( NULL == p ) return E_INVALIDARG;

		p->m_pIndexBuffer = NULL;
		p->m_pVertexBuffer = NULL;
		p->m_LastUpdated = 0;
		p->m_PipeLength = 0;

		HRESULT hr = S_OK;



		// 2] Define the vertex buffer
		// ---------------------------
		D3D10_BUFFER_DESC vbDesc;
		ZeroMemory( &vbDesc, sizeof( D3D10_BUFFER_DESC ) );

		p->m_VertexCount = MaximumPipeLength * ( 2 + Constants::StacksPerPipeSegment ) * Constants::SlicesPerPipeSegment;

		vbDesc.ByteWidth = p->m_VertexCount * sizeof( SimpleVertex );
		vbDesc.Usage = D3D10_USAGE_DYNAMIC;
		vbDesc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
		vbDesc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;

		m_VRAMBytes += vbDesc.ByteWidth;



		// 3] Create the vertex buffer
		// ---------------------------
		hr = pDevice->CreateBuffer( &vbDesc, NULL, &p->m_pVertexBuffer );
		if( FAILED( hr ) )
		{
			ERR_OUT( L"Failed to create the vertex buffer!" );

			return hr;
		}



		// 4] Define the index buffer
		// --------------------------
		D3D10_BUFFER_DESC ibDesc;
		ZeroMemory( &ibDesc, sizeof( D3D10_BUFFER_DESC ) );

		p->m_IndexCount = MaximumPipeLength * ( 1 + Constants::StacksPerPipeSegment ) * Constants::SlicesPerPipeSegment * 6;

		ibDesc.ByteWidth = p->m_IndexCount * sizeof( UINT32 );
		ibDesc.Usage = D3D10_USAGE_DYNAMIC;
		ibDesc.BindFlags = D3D10_BIND_INDEX_BUFFER;
		ibDesc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;

		m_VRAMBytes += ibDesc.ByteWidth;



		// 5] Create the index buffer
		// --------------------------
		hr = pDevice->CreateBuffer( &ibDesc, NULL, &p->m_pIndexBuffer );
		if( FAILED( hr ) )
		{
			ERR_OUT( L"Failed to create the index buffer!" );

			return hr;
		}



		// 6] Acquire the rendering technique
		// ----------------------------------
		p->m_pTechnique =  m_pEffect->GetTechniqueByName( "SimpleRendering" );

		if( !p->m_pTechnique->IsValid() )
		{
			// No technique by this name exists!
			ERR_OUT( L"Unable to acquire a reference to the 'SimpleRendering' technique." );

			return E_NOINTERFACE;
		}



		// 6] Fill in the vertex declaration
		// ---------------------------------
		D3D10_INPUT_ELEMENT_DESC vertex_desc[] = 
		{
			{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
			{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D10_APPEND_ALIGNED_ELEMENT, D3D10_INPUT_PER_VERTEX_DATA, 0 },
			{ "WEIGHT", 0, DXGI_FORMAT_R32_FLOAT, 0, D3D10_APPEND_ALIGNED_ELEMENT, D3D10_INPUT_PER_VERTEX_DATA, 0 }
		};

		UINT ElementCount = sizeof(vertex_desc) / sizeof( D3D10_INPUT_ELEMENT_DESC );



		// 7] Create the input layout
		// --------------------------
		D3D10_TECHNIQUE_DESC techDesc;
		p->m_pTechnique->GetDesc( &techDesc );
		p->m_ppInputLayouts = new ID3D10InputLayout*[ techDesc.Passes ];

		for( UINT i = 0; i < techDesc.Passes; ++i )
		{
			D3D10_PASS_DESC passDesc;
			p->m_pTechnique->GetPassByIndex(i)->GetDesc( &passDesc );
			hr = pDevice->CreateInputLayout( vertex_desc, ElementCount, passDesc.pIAInputSignature, passDesc.IAInputSignatureSize, &p->m_ppInputLayouts[i] );

			if( FAILED( hr ) )
			{
				ERR_OUT( L"Unable to generate input layout to match pass from technique" );

				p->m_pTechnique = NULL;

				return hr;
			}
		}

		return hr;
	}



	HRESULT ForwardRenderer::UpdateIndividualPipe( PipeResources* p, const Utils::CoordinateList& coords, const UINT16& xSize, const UINT16& ySize, const UINT16& zSize, const UINT32& CurrLen )
	{
		HRESULT hr = S_OK;

		// Generate scaling aliases
		// ------------------------
		float fX = 1.0f / static_cast< float >( xSize );
		float fY = 1.0f / static_cast< float >( ySize );
		float fZ = 1.0f / static_cast< float >( zSize );
		float fWeightMul = 1.0f / static_cast< float >( CurrLen );

		// The centre point of a pipe segment is (x * fX - 0.5) to generate the whole
		// grid inside a 1x1x1 cube centred about the origin.

		// Default to X in case all dimensions are equal
		float PipeSize = fX;

		// Pick the smallest dimension as the basis for pipe size
		if( (abs(xSize) < abs(ySize)) && (abs(xSize) < abs(zSize)) )
		{
			// X is smallest
			PipeSize = fX;
		}
		else if( (abs(ySize) < abs(xSize)) && (abs(ySize) < abs(zSize)) )
		{
			// Y is  smallest
			PipeSize = fY;
		}
		else if( (abs(zSize) < abs(xSize)) && (abs(zSize) < abs(ySize)) )
		{
			// Z is smallest
			PipeSize = fZ;
		}

		PipeSize *= 0.5f;
		PipeSize *= Constants::MaximumPipeSize;

		// Update the vertex data
		// ----------------------
		SimpleVertex *pVerts;

		if( SUCCEEDED( p->m_pVertexBuffer->Map( D3D10_MAP_WRITE_DISCARD, 0, reinterpret_cast< void** >( &pVerts ) ) ) )
		{
			for( UINT segment = 0; segment < CurrLen; ++segment )
			{
				// Determine the mid-point for this pipe segment
				D3DXVECTOR3 mid_point;

				mid_point.x = ((2.0f * static_cast< float >( coords.at(segment).x ) + 1.0f) / (2.0f * static_cast< float >( xSize ))) - 0.5f;
				mid_point.y = ((2.0f * static_cast< float >( coords.at(segment).y ) + 1.0f) / (2.0f * static_cast< float >( ySize ))) - 0.5f;
				mid_point.z = ((2.0f * static_cast< float >( coords.at(segment).z ) + 1.0f) / (2.0f * static_cast< float >( zSize ))) - 0.5f;

				// Determine the incoming vector: previous->current
				Utils::IntegerVector InVec;
				if( segment < 1 ) // Can't use (segment-1)<0 due to segment being UINT
				{
					// special case: incoming vector at the first segment should just
					// be a copy of the outgoing vector as there are no previous segments
					InVec.x = coords.at( segment + 1 ).x - coords.at( segment ).x;
					InVec.y = coords.at( segment + 1 ).y - coords.at( segment ).y;
					InVec.z = coords.at( segment + 1 ).z - coords.at( segment ).z;
				}
				else
				{
					// expected case: do a simple (to - from) vector calculation
					InVec.x = coords.at( segment ).x - coords.at( segment - 1 ).x;
					InVec.y = coords.at( segment ).y - coords.at( segment - 1 ).y;
					InVec.z = coords.at( segment ).z - coords.at( segment - 1 ).z;
				}

				// Construct a matrix to represent the incoming vector
				D3DXMATRIX mIn = GetRotationMatrixForVector( InVec );

				// Determine the outgoing vector: current->next
				Utils::IntegerVector OutVec;
				if( (segment + 1) >= coords.size() )
				{
					// special case: outgoing vector at the last segment has to be the
					// same as the incoming vector as there are no further segments
					OutVec.x = coords.at( segment ).x - coords.at( segment - 1 ).x;
					OutVec.y = coords.at( segment ).y - coords.at( segment - 1 ).y;
					OutVec.z = coords.at( segment ).z - coords.at( segment - 1 ).z;
				}
				else
				{
					// expected case: do a simple (to - from) vector calculation
					OutVec.x = coords.at( segment + 1 ).x - coords.at( segment ).x;
					OutVec.y = coords.at( segment + 1 ).y - coords.at( segment ).y;
					OutVec.z = coords.at( segment + 1 ).z - coords.at( segment ).z;
				}

				// Construct a matrix to represent the outgoing vector
				D3DXMATRIX mOut = GetRotationMatrixForVector( OutVec );

				// Now create a pipe segment around this mid-point
				CreatePipeSegment( &pVerts[ segment * (( 2 + Constants::StacksPerPipeSegment ) * Constants::SlicesPerPipeSegment)], mid_point, fY, PipeSize, static_cast< float >( segment ) * fWeightMul, mIn, mOut );
			}
			OutputDebugString( L"\n" );

			p->m_pVertexBuffer->Unmap( );

		}

		// Update the index data
		// ---------------------
		UINT32 *pIndices;
		UINT32 CurrentIndex = 0;

		if( SUCCEEDED( p->m_pIndexBuffer->Map( D3D10_MAP_WRITE_DISCARD, 0, reinterpret_cast< void** >( &pIndices ) ) ) )
		{
			for( UINT32 segment = 0; segment < CurrLen; ++segment )
			{
				const UINT32 SegmentBaseIndex = ( 2 + Constants::StacksPerPipeSegment ) * Constants::SlicesPerPipeSegment * segment;

				for( UINT32 stack = 0; stack < (1 + Constants::StacksPerPipeSegment); ++stack )
				{
					UINT32 StackBaseIndex = stack * Constants::SlicesPerPipeSegment;

					// For each slice we want to create an indexed line
					// between the vertex on this stack and the vertex on the next stack
					for( UINT32 slice = 0; slice < Constants::SlicesPerPipeSegment; ++slice )
					{
						// Create the first triangle
						pIndices[ CurrentIndex + 0 ] = SegmentBaseIndex + StackBaseIndex + slice;
						pIndices[ CurrentIndex + 1 ] = SegmentBaseIndex + StackBaseIndex + ((slice + 1) % Constants::SlicesPerPipeSegment) + Constants::SlicesPerPipeSegment;
						pIndices[ CurrentIndex + 2 ] = SegmentBaseIndex + StackBaseIndex + slice + Constants::SlicesPerPipeSegment;						

						// Create the second triangle
						pIndices[ CurrentIndex + 3 ] = SegmentBaseIndex + StackBaseIndex + slice;
						pIndices[ CurrentIndex + 4 ] = SegmentBaseIndex + StackBaseIndex + ((slice + 1) % Constants::SlicesPerPipeSegment);
						pIndices[ CurrentIndex + 5 ] = SegmentBaseIndex + StackBaseIndex + ((slice + 1) % Constants::SlicesPerPipeSegment) + Constants::SlicesPerPipeSegment;

						CurrentIndex += 6;
					}
				}
			}

			p->m_pIndexBuffer->Unmap( );
		}

		// Update internal state - required for Draw calls
		// -----------------------------------------------
		p->m_PipeLength = CurrLen;

		return hr;
	}



	HRESULT ForwardRenderer::DestroyIndividualPipe( PipeResources* p )
	{
		if( NULL == p )
			return E_INVALIDARG;

		if( (NULL != p->m_pTechnique) && p->m_pTechnique->IsValid() )
		{
			D3D10_TECHNIQUE_DESC techDesc;
			p->m_pTechnique->GetDesc( &techDesc );

			for( UINT i = 0; i < techDesc.Passes; ++i )
			{
				SAFE_RELEASE( p->m_ppInputLayouts[i] );
			}

			SAFE_DELETE_ARRAY( p->m_ppInputLayouts );
		}
		

		SAFE_RELEASE( p->m_pIndexBuffer );
		SAFE_RELEASE( p->m_pVertexBuffer );

		return S_OK;
	}

	void ForwardRenderer::CreatePipeSegment( SimpleVertex* ppDestination, const D3DXVECTOR3& mid_point, const float& height, const float& width, const float& weight, const D3DXMATRIX& mCurr, const D3DXMATRIX& mNext )
	{
		// Construct both matrices
		D3DXMATRIX m1;
		D3DXMATRIX m2;
		D3DXMATRIX n1;
		D3DXMATRIX n2;
		D3DXMATRIX mTemp;

		// First: Translate and rotate for this segment
		D3DXMatrixTranslation( &m1, -mid_point.x, -mid_point.y, -mid_point.z );
		D3DXMatrixMultiply( &m1, &m1, &mCurr );
		
		D3DXMatrixTranslation( &mTemp, mid_point.x, mid_point.y, mid_point.z );
		D3DXMatrixMultiply( &m1, &m1, &mTemp );

		// Second: Translate and rotate for the next segment
		D3DXMatrixTranslation( &m2, -mid_point.x, -mid_point.y, -mid_point.z );
		D3DXMatrixMultiply( &m2, &m2, &mNext );
		
		D3DXMatrixTranslation( &mTemp, mid_point.x, mid_point.y, mid_point.z );
		D3DXMatrixMultiply( &m2, &m2, &mTemp );

		// Now create the inverse-transpose of m1
		D3DXMatrixInverse( &n1, NULL, &m1 );
		D3DXMatrixTranspose( &n1, &n1 );

		// Now create the inverse-transpose of m2
		D3DXMatrixInverse( &n2, NULL, &m2 );
		D3DXMatrixTranspose( &n2, &n2 );

		UINT current_vertex = 0;

		for( UINT stack = 0; stack < (2 + Constants::StacksPerPipeSegment); ++stack )
		{
			float s = (static_cast< float >( stack ) / static_cast< float >(1 + Constants::StacksPerPipeSegment));
			float h = (mid_point.y - (height / 2.0f)) + height * s;

			for( UINT slice = 0; slice < Constants::SlicesPerPipeSegment; ++slice )
			{
				float angle = 2.0f * D3DX_PI * (static_cast< float >( slice ) / static_cast< float >( Constants::SlicesPerPipeSegment ));

				ppDestination[current_vertex].p.x = mid_point.x + width * sinf(angle);
				ppDestination[current_vertex].p.y = h;
				ppDestination[current_vertex].p.z = mid_point.z + width * cosf(angle);

				// Transform with the first matrix
				D3DXVECTOR3 p1;
				D3DXVec3TransformCoord( &p1, &ppDestination[current_vertex].p, &m1 );

				// Transform with the second matrix
				D3DXVECTOR3 p2;
				D3DXVec3TransformCoord( &p2, &ppDestination[current_vertex].p, &m2 );

				// Lerp between the positions according to 's'
				D3DXVec3Lerp( &ppDestination[current_vertex].p, &p1, &p2, s );

				// Set up the weight coefficient
				ppDestination[current_vertex].w = weight;

				// Generate the per-vertex normal
				ppDestination[current_vertex].n = D3DXVECTOR3( sinf(angle), 0.0f, cosf(angle) );

				// Due to performing software transformation we need to also transform
				// the per-vertex normal.
				D3DXVec3TransformNormal( &p1, &ppDestination[current_vertex].n, &n1 );
				D3DXVec3TransformNormal( &p2, &ppDestination[current_vertex].n, &n2 );
				//D3DXVec3Add( &ppDestination[current_vertex].n, &p1, &p2 );
				D3DXVec3Lerp( &ppDestination[current_vertex].n, &p1, &p2, s );
				D3DXVec3Normalize( &ppDestination[current_vertex].n, &ppDestination[current_vertex].n );
				

				++current_vertex;
			}
		}
	}



	D3DXMATRIX ForwardRenderer::GetRotationMatrixForVector( const Utils::IntegerVector& vec )
	{
		D3DXMATRIX mRet;
		D3DXMatrixIdentity( &mRet );

		// Handle vectors going in/out along the X axis
		if( (vec.x != 0) && (vec.y == 0) && (vec.z == 0) )
		{
			if( vec.x < 0 )
			{
				D3DXMatrixRotationZ( &mRet, D3DX_PI / 2.0f );
			}
			else
			{
				D3DXMatrixRotationZ( &mRet, -D3DX_PI / 2.0f );
			}
		}

		// Handle vectors going in/out along the Y axis
		if( (vec.x == 0) && (vec.y != 0) && (vec.z == 0) )
		{
			if( vec.y < 0 )
			{
				D3DXMatrixScaling( &mRet, 1.0f, -1.0f, 1.0f );
			}
			else
			{
				/* NOP */
			}
		}

		// Handle vectors going in/out along the Z axis
		if( (vec.x == 0) && (vec.y == 0) && (vec.z != 0) )
		{
			if( vec.z < 0 )
			{
				D3DXMatrixRotationX( &mRet, -D3DX_PI / 2.0f );
			}
			else
			{
				D3DXMatrixRotationX( &mRet, D3DX_PI / 2.0f );
			}
		}

		return mRet;
	}

};